#ifndef __USB_FP_PROTOCOL__
#define __USB_FP_PROTOCOL__

#include <stdint.h>
#include "uapi_usb.h"
#include "ofp_prot_common.h"
#ifdef __cplusplus
extern "C" {
#endif

#define USB_BUFFER_SIZE   (201)
#define CHIP_CHECKSUM_SIZE      2


/***********************枚举类型************************/

typedef enum {
    FP_CONTROL_FLAG_IDLE =0,
    FP_CONTROL_FLAG_STOPPED = 1,
    FP_CONTROL_FLAG_TIMEOUT,
    FP_CONTROL_FLAG_DEV_NOT_EXIST,
    FP_CONTROL_FLAG_ENROLLID_OUT_RANGE,
} control_flag;


//协议包标识类型
typedef enum {
    PROT_TYPE_CMD       = 0x01,
    PROT_TYPE_DATA      = 0x02,
    PROT_TYPE_RESPOND   = 0x07,
    PROT_TYPE_END       = 0x08,
} prot_type;

//协议指令类型
typedef enum {
    PROT_CMD_NULL  = 0x00,          //新增加空指令
    PROT_CMD_GETIMAGE = 0x01,       //验证用获取图像
    PROT_CMD_GENCHAR = 0x02,        //根据原始图像生成指纹特征存于文件缓冲区
    PROT_CMD_MATCH = 0x03,          //精确比对特征文件缓冲区中的特征文件
    PROT_CMD_SEARCH = 0x04,         //以特征文件缓冲区中的特征文件搜索整个或部分指纹库
    PROT_CMD_REGMODEL = 0x05,       //将特征文件合并生成模板存于特征文件缓冲区
    PROT_CMD_STORECHAR = 0x06,      //将特征缓冲区中的文件储存到flash指纹库中
    PROT_CMD_LOADCHAR = 0x07,       //从 flash 指纹库中读取一个模板到特征缓冲区
    PROT_CMD_UPCHAR = 0x08,         //将特征缓冲区中的文件上传给上位机
    PROT_CMD_DOWNCHAR = 0x09,       //从上位机下载一个特征文件到特征缓冲区
    PROT_CMD_UPIMAGE = 0x0A,        //上传原始图像
    PROT_CMD_DOWNIMAGE = 0x0B,      //下载原始图像
    PROT_CMD_DELCHAR = 0x0C,        //删除 flash 指纹库中的一个特征文件
    PROT_CMD_EMPTY = 0x0D,          //清空 flash 指纹库
    PROT_CMD_READSYSPARA = 0x0F,    //读系统基本参数
    PROT_CMD_SETPWD = 0x12,         //设置设备握手口令
    PROT_CMD_VFYPWD = 0x13,         //验证设备握手口令

    PROT_CMD_SETCHIPADDR = 0x15,    //设置芯片地址
    PROT_CMD_READINFOPAGE = 0x16,   //读取 FLASH Information Page 内容
    PROT_CMD_HIGHSPEEDSEARCH = 0x1B,    //高速搜索FLASH
    PROT_CMD_VALIDTEMPLATENUM = 0x1D,   //读有效模板个数
    PROT_CMD_READINDEXTABLE = 0x1F,     //读索引表
    PROT_CMD_GETENROLLIMAGE = 0x29, //注册用获取图像
    PROT_CMD_CANCEL = 0x30,         //取消指令
    PROT_CMD_AUTOENROLL = 0x31,     //自动注册模块指令
    PROT_CMD_AUTOIDENTIFY = 0x32,   //自动验证指纹指令
    PROT_CMD_SLEEP = 0x33,          //休眠指令
    PROT_CMD_GETCHIPSN = 0x34,      //获取芯片唯一序列号
    PROT_CMD_HANDSHAKE = 0x35,      //握手指令
    PROT_CMD_CHECKSENSOR = 0x36,    //校验传感器
    PROT_CMD_IIC_LED_CONTROL = 0x40,//IIC接口灯光控制

    PROT_CMD_PS_PC_STATE = 0x50,//下发PC状态

    PROT_CMD_TEST_TYPE = 0xAF,          //生产测试命令

    /*********************用于BF91360ML*********************/
    PORT_CMD_SET_BRIGHTNESS = 0xB0,     //设置采集器亮度, add by hcq, 20221229
    PORT_CMD_GET_BRIGHTNESS = 0xB1,     //获取采集器当前亮度
    PORT_CMD_SET_CONTRAST = 0xB2,       //设置采集器当前对比度
    PORT_CMD_GET_CONTRAST = 0xB3,       //获取采集器当前对比度
    PORT_CMD_GET_MAXSIZEOFIMAGE = 0xB4, //获取采集器图片尺寸最大值
    PORT_CMD_SET_SIZEOFIMAGE = 0xB5,    //设置采集器当前图片坐标X，坐标Y，宽度，高度
    PORT_CMD_GET_SIZEOFIMAGE = 0xB6,    //获取采集器当前图片坐标X，坐标Y，宽度，高度
    PORT_CMD_READYCAPIMAGE = 0xB7,      //准备采集一帧图像
    PORT_CMD_STARTCAPIMAGE = 0xB8,      //采集一帧图像
    PORT_CMD_ENDCAPIMAGE = 0xB9,        //结束采集一帧图像

    PORT_CMD_ACQUIRE_IMAGEDATA = 0xF0,  //自定义获取图像数据状态, add by hcq, 20230118
    /*******************************************************/

    PROT_CMD_RTBOOT = 0xFF, //返回boot状态，便于下次重烧固件
} prot_cmd_enum;

typedef enum
{
    PROT_SUBCMD_NULL = 0x00,         // 新增加空指令
    PROT_SUBCMD_READ_FW = 0x10,         //读取固件版本号
    PROT_SUBCMD_RW_REG = 0x11,          //读写寄存器
    PROT_SUBCMD_FP_DOWN = 0x13,         //检测手指按下
    PROT_SUBCMD_SIMFP_DOWN = 0x14,      //检测假手指按下

    PROT_SUBCMD_DEADPIXEL = 0x18,       //坏点检测
    PROT_SUBCMD_CLEAR_IRQ = 0x19,       //清除sensor中断
    PROT_SUBCMD_SENSORINIT = 0x22,      //Sensor init 初始化结果
    PROT_SUBCMD_SELFCHECK = 0x31,       //自检指令
    PROT_SUBCMD_SPI_TEST = 0x32,        //进入图像质量测试模式
    PROT_SUBCMD_OTP_WRITE = 0x34,       //OTP信息烧录模式
    PROT_SUBCMD_OTP_READ = 0x35,        //OTP信息读取模式
    PROT_SUBCMD_SPI_INT = 0x36,         //检测SPI中断信号
    PROT_SUBCMD_I2C_INT = 0x37,         //检测I2C中断信号
    PROT_SUBCMD_RECOVER_FACTORY = 0x38, //恢复出厂设置
    PROT_SUBCMD_EXFLASH_ID = 0x39,      //获取片外flashID

    PROT_SUBCMD_SET_MODE = 0xbd,            //设置用户模式或调试模式
} prot_subcmd_enum;

#define PROT_CMD_DEBUG_TYPE             0xDE        //调试指令 de 01: 打开调试指令，de 00：关闭调试

typedef enum {
    PROT_RESP_OK = 0x00,
    PROT_RESP_DATA_RECV_ERR = 0x01,         //数据包接收错误
    PROT_RESP_NO_FINGER = 0x02,             //传感器上无手指
    PROT_RESP_ENROLL_FAULT = 0x03,          //录入指纹图像失败
    PROT_RESP_IMG_TOO_DRY = 0x04,           //录入指纹图像太干、太淡而生不成特征
    PROT_RESP_IMG_TOO_WET = 0x05,           //录入指纹图像太湿、太糊而生不成特征
    PROT_RESP_IMG_TOO_CHAOTIC = 0x06,       //录入指纹图像太乱而生不成特征
    PROT_RESP_FEATURE_TOO_LOW = 0x07,       //指纹图像特征点太少（或面积太小）而生不成特征
    PROT_RESP_FPRINT_MISMATCH = 0x08,       //指纹不匹配
    PROT_RESP_FPRINT_NOT_FIND = 0x09,       //没搜索到指纹
    PROT_RESP_FEATURE_MERGE_FAULT = 0x0A,   //特征合并失败
    PROT_RESP_ADDR_OUT_RANGE = 0x0B,        //访问指纹库时地址范围超出
    PROT_RESP_READ_TEMPLATE_FAULT = 0x0C,   //从指纹库读模板出错或无效
    PROT_RESP_UPLOAD_FEATURE_FAULT = 0x0D,  //上传特征失败
    PROT_RESP_CANT_RECV_PKG = 0x0E,         //模块不能接收后续数据包
    PROT_RESP_UPLOAD_IMG_FAULT = 0x0F,      //上传图像失败
    PROT_RESP_DEL_TEMPLATE_FAULT = 0x10,    //删除模板失败
    PROT_RESP_CLEAN_FPRINTLIB_FAULT = 0x11, //清空指纹库失败
    PROT_RESP_CANTBE_LOWPOWER_STATE = 0x12, //不能进入低功耗状态
    PROT_RESP_CMD_ERR = 0x13,               //口令不正确
    PROT_RESP_RESET_FAULT = 0x14,           //系统复位失败
    PROT_RESP_NO_RAWIMG_IN_BUFFER = 0x15,   //缓冲区内没有原始图而生不成图像
    PROT_RESP_UPGRADE_FAULT = 0x16,         //在线升级失败
    PROT_RESP_FINGER_NO_MOVE = 0x17,        //残留指纹或两次采集之间手没有移动过
    PROT_RESP_WR_FLASH_FAULT = 0x18,        //读写FLASH出错
    PROT_RESP_CREATE_RANDOM_NUM_FAULT = 0x19,   //随机数生成失败
    PROT_RESP_NOT_VALID_REG_NUM = 0x1A,     //无效寄存器号
    PROT_RESP_REG_VALUE_ERR = 0x1B,         //寄存器设定内容错误号
    PROT_RESP_NOTEPAD_PAGE_NUM_ERR = 0x1C,  //记事本页码指定错误
    PROT_RESP_OPT_PORT_FAULT = 0x1D,        //端口操作失败
    PROT_RESP_AUTO_REGISTER_FAULT = 0x1E,   //自动注册失败
    PROT_RESP_FPRINTLIB_FULL = 0x1F,        //指纹库满
    PROT_RESP_DEV_ADDR_ERR = 0x20,          //设备地址错误
    PROT_RESP_PASSWORD_ERR = 0x21,          //密码有误
    PROT_RESP_TEMPLATE_NOT_EMPTY = 0x22,    //指纹模板非空
    PROT_RESP_TEMPLATE_EMPTY = 0x23,        //指纹模板为空
    PROT_RESP_FPRINTLIB_EMPTY = 0x24,       //指纹库空
    PROT_RESP_ENROLL_TIMES_ERR = 0x25,      //录入次数设置错误
    PROT_RESP_TIMEOUT = 0x26,               //超时
    PROT_RESP_FPRINT_EXIST = 0x27,          //指纹已存在
    PROT_RESP_TEMPLATE_RELATED = 0x28,      //指纹模板有关联
    PROT_RESP_SENSOR_INIT_FAULT = 0x29,     //传感器初始化失败

    PROT_RESP_POSITION_REPEATED = 0x30,     //位置重复
    PROT_RESP_FPRINT_QUALITY_BAD = 0x31,    //指纹质量不佳
    PROT_RESP_FPRINT_AREA_TOO_SMALL = 0x32, //指纹面积过小

    PROT_RESP_DATA_RECV_OK = 0xF0,          //有后续数据包的指令，正确接收后用0xf0应答
    PROT_RESP_DATA_CMD_RECV_OK = 0xF1,      //有后续数据包的指令，命令包用0xf1应答

    PROT_RESP_PROG_FLASH_CHECKSUM_ERR = 0xF2,       //烧写内部FLASH时，校验和错误
    PROT_RESP_PROG_FLASH_PKGTYPE_ERR = 0xF3,        //烧写内部FLASH时，包标识错误
    PROT_RESP_PROG_FLASH_PKGLEN_ERR = 0xF4,         //烧写内部FLASH时，包长度错误
    PROT_RESP_PROG_FLASH_PKGLEN_TOO_LANG = 0xF5,    //烧写内部FLASH时，包长度太长
    PROT_RESP_PROG_FLASH_FAULT = 0xF6,              //烧写内部FLASH失败

} prot_cmd_resp_enum;

typedef struct
{
    uint16_t pkg_head;      //包头，固定为0xEF01
    uint32_t chip_addr;    //芯片地址,默认为0xffffffff
    uint8_t  pkg_flag;  //包标识
    uint16_t  data_len; //包长度
}__attribute__((packed))msg_header;

//msg_struct 64 byte
typedef struct
{
    msg_header head;      //消息头部
    uint8_t data[USB_BUFFER_SIZE];
}__attribute__((packed))msg_struct;


typedef struct
{
    uint8_t cmd;
    uint8_t subcmd;
    uint8_t send_data[USB_BUFFER_SIZE];
    uint16_t send_data_len;
    uint8_t recv_data[USB_BUFFER_SIZE];
    uint16_t recv_data_len;
} cmd_struct;

/*协议包数据结构*/
typedef struct
{
    uint8_t  prot_state;          //串口协议解析状态
    uint16_t prot_head;
    uint32_t prot_addr;
    uint8_t  prot_type;
    uint16_t prot_size;
    uint8_t  prot_data[USB_BUFFER_SIZE];  //保存上位机的参数数据
    uint32_t prot_data_cnt;       //对数据长度进行计数
    uint16_t prot_checksum;
    uint8_t  prot_respond;        //给host的应答
    uint8_t  prot_source;         //数据从UART或SPI过来的,UART:0 ;SPI:1

    uint8_t  current_cmd_code;    //当前发送的指令码, add by hcq, 20230117
    uint8_t  current_resp_cmd;    //当前应答的命令
    uint8_t  current_resp_type;   //当前应答结果
    //uint8  recv_prot_type;
    uint8_t  current_sub_cmd_code;    //生产测试模式下的子指令码
} prot_packet;

/*标识包处理状态机*/
typedef enum
{
    PACKET_IDLE = 0,
    PACKET_HEAD,
    PACKET_ADDRESS1,
    PACKET_ADDRESS2,
    PACKET_ADDRESS3,
    PACKET_ADDRESS4,
    PACKET_TYPE,
    PACKET_SIZE1,
    PACKET_SIZE2,
    PACKET_DATA,
    PACKET_CHECKSUM1,
    PACKET_CHECKSUM2,
    PACKET_ERROR = 100,  //包出错
} packet_status;

typedef enum
{
    CONFIRM_CODE_SUCCESS = 0x00,  //执行成功
    CONFIRM_CODE_CMD_ERROR = 0x01,//指令错误
    CONFIRM_CODE_EXECUTE_FAILED = 0x02, //执行失败
} confirm_code;


/*系统基本参数，待确认格式*/
typedef struct
{
    uint16_t sensor_type;         //传感器类型
    uint16_t fp_database_size;    //指纹库容量
    uint16_t security_level;      //安全等级
    uint32_t device_addr;         //设备地址
} sys_param;

typedef enum
{
    PROT_SUCCESS = 0,
    PROT_ERROR_TRANSFER = -1,
    PROT_ERROR_PARSE = -2,
    PROT_ERROR_OTHER = -3,

} prot_err;

/*读取数据操作相关参数*/
typedef struct {
    uint32_t recv_len;            //串口协议解析状态
    uint16_t wait_ms;             //首次读取数据间隔时间
    uint16_t cycle_times;         //未读到数据时循环读取次数, 至少循环1次
    uint16_t cycle_ms;            //循环等待时间
} ofp_recv_data_param;

typedef struct {
    uint16_t id;
    uint8_t times;
    uint16_t param;
} ofp_enroll_input_setting;

typedef struct {
    uint8_t secure_level;
    uint16_t fp_id;
    uint16_t system_id;
} ofp_identify_input_setting;

int32_t ofp_usb_get_firmware_version(uapi_usb_handle *handle, ofp_firmware_version *fw_ver);
int32_t ofp_usb_goto_boot(uapi_usb_handle *handle);
int32_t ofp_usb_read_index_table(uapi_usb_handle *handle, uint8_t page_number, ofp_index_table *table);
int32_t ofp_usb_empty(uapi_usb_handle *handle);
int32_t ofp_usb_delete_template(uapi_usb_handle *handle, uint16_t enroll_id, uint16_t num);
int32_t ofp_usb_cancel(uapi_usb_handle *handle);
int32_t ofp_usb_auto_enroll(uapi_usb_handle *handle, ofp_enroll_input_setting in_set, ofp_enroll_result *result);
int32_t ofp_usb_get_enroll_result(uapi_usb_handle *handle, ofp_enroll_result *result);
int32_t ofp_usb_auto_identify(uapi_usb_handle *handle, ofp_identify_input_setting in_set, ofp_identify_result *result);
int32_t ofp_usb_get_identify_result(uapi_usb_handle *handle, ofp_identify_result *result);


#ifdef __cplusplus
}
#endif

#endif


